#include "pull/Pull.h"
#include "globalinfo.h"
#include "NodeHandler.h"
#include <string.h>
#include <iostream>
#include <sys/stat.h>
namespace Cli::Pull {
    std::list<FileInfo> taskQueue;
    size_t total_count = 0;
    size_t finish = 0;
    unsigned long long total_size = 0;
    void execute() {
        char path[8192] = {0};
        auto executor = nodeHandler.getClientTaskExecutor(TaskFlag::get);
        size_t pos;
        strcpy(path, configReader.getConfig(CONFIG_RESOURCE_DIR, CONFIG_RESOURCE_DIR_DEFAULT).c_str());
        pos = strlen(path);
        path[pos++] = '/';
        total_count = taskQueue.size();
        socketinf sock;
        sock.socket_fd = -1;
        while ( taskQueue.size() != 0 )  {
            printf("[%ld/%ld] %s\n", finish+1, total_count, taskQueue.front().name.c_str());
            try {
                if (sock.socket_fd == -1) {
                    sock = nodeHandler.getMasterConnect();
                }
                if(taskQueue.front().type == FileUtils::fileType::dir) {
                    strcpy(path + pos, taskQueue.front().name.c_str());
                    FileUtils::mkdirs(path);
                } else {
                    executor->clientAction(sock,  taskQueue.front().name.c_str(), taskQueue.front().name.length());
                }
                finish ++;
                taskQueue.pop_front();
            } catch(const Exception& e) {
                sock.socket_fd = -1;
                std::cout << "Error - Retry after 5s" << std::endl;
                sleep(5);
            }
        }
        nodeHandler.getClientTaskExecutor(TaskFlag::closetask)->clientAction(sock);
    }

    void fun(std::vector<std::string> &args){
        // 检查运行状态
        if(taskQueue.size() != 0) {
            std::cout << "Pull is running" << std::endl;
            return;
        }
        // 读取路径
        char path[8192] = {0};
        bool exist = false;
        struct stat file_stat;
        strcpy(path, configReader.getConfig(CONFIG_RESOURCE_DIR, CONFIG_RESOURCE_DIR_DEFAULT).c_str());
        size_t pos = strlen(path);                  // 记录基本路径末尾位置
        path[pos++] = '/';
        nodeHandler.executeClientTask(TaskFlag::getfilelist);   //  执行getfilelist任务获取远程文件列表
        auto end = globalInfo.remoteFileList.end();
        bool isdir = false;
        for (auto i = globalInfo.remoteFileList.begin(); i != end; i++) {
            //  在基本路径末尾加上资源路径
            strcpy(path + pos, i->name.c_str());

            // 判断本地文件是否存在或文件大小是否一致，不存在或大小不一致则添加资源文件到任务队列
            exist = access(path, F_OK) == 0;
            if (exist) {
                stat(path, &file_stat);
                isdir = S_ISDIR(file_stat.st_mode);
                if( !isdir && file_stat.st_size != i->size ) {
                    taskQueue.push_back(*i);
                    ++total_count;
                    if(!isdir) {
                        std::cout << "[Warning] file will be overwrite：" << i->name << std::endl;
                        total_size += i->size;
                    }
                }
            } else {
                taskQueue.push_back(*i);
                ++total_count;
                total_size += i->size;
            }
        }
        std::cout << "======================================" << std::endl;
        std::cout << "Need to get files count : " << taskQueue.size() << std::endl;
        std::cout << "Need to get files size  : " << FileUtils::toSizeString(total_size) << std::endl;
        if(taskQueue.size() != 0 ) {
        std::cout << "Continue? [y/n]: ";
            char input[1024];
            std::cin.getline(input, 1024);
            if(input[0] == 'Y' || input[0] == 'y') {
                std::cout << "start pull" << std::endl;
                // 后期使用多线程执行这个 目前测试只用单线程
                execute();
            } else {
                std::cout << "Abort" << std::endl;
                taskQueue.clear();
            }
        } else {
            std::cout << "======================================" << std::endl;
            std::cout << "Nothing need to do" << std::endl;
        }
        finish = 0;
        total_size = 0;
        total_count = 0;
    }
}
MAKE_CLI_EXECUTOR(Pull, "pull", "pull all file from master", {
    Cli::Pull::fun(args);
})
